﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using CalcEngine;
using CalcEngine.Phrase;

namespace TestProject1
{
    /// <summary>
    /// Summary description for CalculationEngineTest
    /// </summary>
    [TestClass]
    public class CalculationEngineTest
    {
        public CalculationEngineTest()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        [TestMethod]
        public void CalculationTest1()
        {
            using (CalculationContext context = new CalculationContext())
            {
                context.Analyze("1+2+3#=");
                CalculationEngine ce = new CalculationEngine(context);
                Assert.AreEqual(0.0, context.ANS);
            ce.Run();
                Assert.AreEqual(6.0, context.ANS);
            }
        }
        [TestMethod]
        public void CalculationTest2()
        {
            using (CalculationContext context = new CalculationContext())
            {
                context.Analyze("1+(2*3-5)/2#=");
                CalculationEngine ce = new CalculationEngine(context);
            ce.Run();
                Assert.AreEqual(1.5, context.ANS);
            }
        }
        [TestMethod]
        public void CalculationTest3()
        {
            using (CalculationContext context = new CalculationContext())
            {
                context.Analyze("1+(2*3-1)/2=");
                CalculationEngine ce = new CalculationEngine(context);
            ce.Run();
                Assert.AreEqual(3.5, context.ANS);
            }
        }
        [TestMethod]
        public void CalculationTest4()
        {
            using (CalculationContext context = new CalculationContext())
            {
                context.Analyze("asin(sin90*5/5.00+cos90)=");
                CalculationEngine ce = new CalculationEngine(context);
            ce.Run();
                Assert.AreEqual(90, context.ANS);
            }
        }
        [TestMethod]
        public void CalculationTest5()
        {
            using (CalculationContext context = new CalculationContext())
            {
                context.Analyze("2^(2+4)=");
                CalculationEngine ce = new CalculationEngine(context);
            ce.Run();
                Assert.AreEqual(Math.Pow(2,6), context.ANS);
            }
        }
        [TestMethod]
        public void CalculationTest6()
        {
            using (CalculationContext context = new CalculationContext())
            {
                context.Analyze("6!=");
                CalculationEngine ce = new CalculationEngine(context);
            ce.Run();
                Assert.AreEqual(720, context.ANS);
            }
        }
        [TestMethod]
        public void CalculationTest7()
        {
            using (CalculationContext context = new CalculationContext())
            {
                context.Analyze("cossin(90)=");
                CalculationEngine ce = new CalculationEngine(context);
            ce.Run();
                Assert.AreEqual(0.999848, context.ANS,0.00001);
            }
        }
        [TestMethod]
        public void CalculationTest8_WrongPhrase()
        {
            using (CalculationContext context = new CalculationContext())
            {
                context.Analyze("loglnlg3=");
                CalculationEngine ce = new CalculationEngine(context);
            try
            {
                ce.Run();
            }
            catch (SyntaxException e)
            {
                Assert.IsTrue(e.Message.Contains("Not enough operands to finish the calculation"));
            }
        }
        }
        [TestMethod]
        public void CalculationTest9()
        {
            using (CalculationContext context = new CalculationContext())
            {
                context.Analyze("5+-1--1=");    
                CalculationEngine ce = new CalculationEngine(context);
                ce.Run();
                Assert.AreEqual(5, context.ANS);
            }
        }
        [TestMethod]
        public void CalculationTest10()
        {
            using (CalculationContext context = new CalculationContext())
            {
                context.Analyze("5---1=");  //same as 5-1
                CalculationEngine ce = new CalculationEngine(context);
                ce.Run();
                Assert.AreEqual(4, context.ANS);
            }
        }
        [TestMethod]
        public void CalculationWithANSTest()
        {
            using (CalculationContext context = new CalculationContext())
            {
                context.Analyze("1+2=");
                CalculationEngine ce = new CalculationEngine(context);
                Assert.AreEqual(0.0, context.ANS);
            ce.Run();
                Assert.AreEqual(3, context.ANS);

                context.Analyze("2+ANS=");
                ce = new CalculationEngine(context);
                ce.Run();
                Assert.AreEqual(5, context.ANS);

                context.Analyze("ANS*2=");
                ce = new CalculationEngine(context);
            ce.Run();
                Assert.AreEqual(10, context.ANS);
            }
        }

        [TestMethod]
        public void CalculationWithVariableTest1()
        {
            using (CalculationContext context = new CalculationContext())
            {
                context.Analyze("1+(2*3-[ax])/2=");
                CalculationEngine ce = new CalculationEngine(context);
                Assert.AreEqual(0.0, context.ANS);
            try
            {
                ce.Run();
            }
            catch (CalculationException e)
            {
                Assert.IsTrue(e.Message.Contains("variable 'ax' not found"));
            }
            context.SetVariable("ax", 5);
            ce.Run();
                Assert.AreEqual(1.5, context.ANS);
            }
        }

        [TestMethod]
        public void CalculationWithVariableTest2()
        {
            using (CalculationContext context = new CalculationContext())
            {
                context.SetVariable("a", 1.56);
                context.SetVariable("b", 1.44);
                context.SetVariable("c", -5);

                context.Analyze("[a]+[b]+[c]=");
                CalculationEngine ce = new CalculationEngine(context);
                Assert.AreEqual(0.0, context.ANS);
                ce.Run();
                Assert.AreEqual(-2, context.ANS);
            }
        }
    }
}
